/// -----------------------------------------------------------------------------------------------------------
/// Module      :  QueueStorageAdapterMetadataBrowseHandler.cs
/// Description :  This class is used for performing a connection-based retrieval of metadata from the target system.
/// -----------------------------------------------------------------------------------------------------------

#region Using Directives

using System;

using Microsoft.ServiceModel.Channels.Common;

#endregion

using BizTalkFactory.Adapters.AzureStorage.StorageAdapterConstants;

namespace BizTalkFactory.Adapters.AzureStorage
{
    internal class AzureStorageAdapterMetadataResolverHandler : AzureStorageAdapterHandlerBase, IMetadataResolverHandler
    {
        public AzureStorageAdapterMetadataResolverHandler(AzureStorageAdapterConnection connection, MetadataLookup metadatalookup)
            : base(connection, metadatalookup)
        {
            
        }

        #region IMetadataResolverHandler Members 

        /// <summary>
        /// Returns a value indicating whether the specified operation metadata is valid
        /// The DateTime field is provided to indicate when this specific operation metadata was last retrieved from the source system.
        /// The method should complete within the specified timespan or throw a timeout exception.
        /// </summary>
        public bool IsOperationMetadataValid(string operationId, DateTime lastUpdatedTimestamp, TimeSpan timeout)
        {
            return true;
        }

        /// <summary>
        /// Returns a value indicating whether the specified type metadata is valid.
        /// The DateTime field is provided to indicate when this specific type metadata was last retrieved from the source system.
        /// The method should complete within the specified timespan or throw a timeout exception.
        /// </summary>
        public bool IsTypeMetadataValid(string typeId, DateTime lastUpdatedTimestamp, TimeSpan timeout)
        {
            return true;
        }

        /// <summary>
        /// Returns an OperationMetadata object resolved from absolute name of the operation metadata object.
        /// The method should complete within the specified time span or throw a timeout exception.
        /// </summary>
        public OperationMetadata ResolveOperationMetadata(string operationId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            string storageName = String.Empty;
            string operationName = String.Empty;
            string objectName = NodeIdHelper.ParseObjectNameFromOperationId(operationId, ref storageName, ref operationName);

            switch (storageName)
            {
                case MetadataSearchBrowseNodeIds.QueueNodePrefix:
                    return ResolveQueueStorageOperationMetadata(objectName, operationName, operationId, out extraTypeMetadataResolved);

                case MetadataSearchBrowseNodeIds.BlobNodePrefix:
                    return ResolveBlobStorageOperationMetadata(objectName, operationName, operationId, out extraTypeMetadataResolved);

                default:
                    throw new AdapterException("Cannot resolve metadata for operation identifier " + operationId);
            }
        }

        

        /// <summary>
        /// Returns a TypeMetadata object resolved from the absolute name of the type metadata object.
        /// The method should complete within the specified time span or throw a timeout exception.
        /// </summary>
        public TypeMetadata ResolveTypeMetadata(string typeId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            extraTypeMetadataResolved = new TypeMetadataCollection();
            throw new AdapterException("Cannot resolve metadata for type identifier " + typeId);
        }

        #endregion

        #region QueueStorage Operations Metadata Resolver Implementation

        private static OperationMetadata ResolveQueueStorageOperationMetadata(string queueName, string operationName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            switch (operationName)
            {
                case OperationNames.ClearMessages:
                    return ResolveQueueStorageClearMessagesOperationMetadata(queueName, operationId, out extraTypeMetadataResolved);

                case OperationNames.DeleteMessage:
                    return ResolveQueueStorageDeleteMessageOperationMetadata(queueName, operationId, out extraTypeMetadataResolved);

                case OperationNames.GetMessage:
                    return ResolveQueueStorageGetMessageOperationMetadata(queueName, operationId, out extraTypeMetadataResolved);

                case OperationNames.PutMessage:
                    return ResolveQueueStoragePutMessageOperationMetadata(queueName, operationId, out extraTypeMetadataResolved);

                default:
                    throw new AdapterException("Cannot resolve metadata for operation identifier " + operationId);
            }
        }

        private static OperationMetadata ResolveQueueStorageClearMessagesOperationMetadata(string queueName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void ClearMessages()
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.ClearMessages);

            // Return Value Void
            om.OperationResult = OperationResult.Empty;

            // ClearMessages
            om.OriginalName = OperationNames.ClearMessages;
            om.OperationGroup = MetadataSearchBrowseNodeIds.QueueNodePrefix + queueName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            return om;
        }

        private static OperationMetadata ResolveQueueStorageDeleteMessageOperationMetadata(string queueName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void DeleteMessage(String MessageID, String PopReceipt)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.DeleteMessage);

            // Return Value Void
            om.OperationResult = OperationResult.Empty;

            // DeleteMessage
            om.OriginalName = OperationNames.DeleteMessage;
            om.OperationGroup = MetadataSearchBrowseNodeIds.QueueNodePrefix + queueName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            // Parameter String MessageId
            om.Parameters.Add(new OperationParameter("MessageId", OperationParameterDirection.In, QualifiedType.StringType, false));

            // Parameter String PopReceipt
            om.Parameters.Add(new OperationParameter("PopReceipt", OperationParameterDirection.In, QualifiedType.StringType, false));

            // Resolve extra parameter type metadata here

            return om;
        }

        private static OperationMetadata ResolveQueueStorageGetMessageOperationMetadata(string queueName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            string getMessageRequestTypeId = SchemaQualifiedType.TypeId(MetadataSearchBrowseNodeIds.QueueNodePrefix, OperationNames.GetMessage);
            string queueMessageTypeName = "QueueMessage" + MetadataTypeIds.GenericType;
            string queueMessageParamName = "QueueMessage";

            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void GetMessage(QueueMessageType QueueMessage)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.GetMessage);

            // Return Value void
            om.OperationResult = OperationResult.Empty;

            // GetMessage
            om.OriginalName = OperationNames.GetMessage;
            om.OperationGroup = MetadataSearchBrowseNodeIds.QueueNodePrefix + queueName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            // Parameter QueueMessageType QueueMessage
            ComplexQualifiedType getMessageRequestParam = new ComplexQualifiedType(getMessageRequestTypeId);
            om.Parameters.Add(new OperationParameter(queueMessageParamName, OperationParameterDirection.In, getMessageRequestParam, false));

            // Resolve extra parameter type metadata here
            extraTypeMetadataResolved.Add(new AzureStorageTypes(getMessageRequestTypeId, queueMessageTypeName));

            return om;
        }

        private static OperationMetadata ResolveQueueStoragePutMessageOperationMetadata(string queueName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            string putMessageRequestTypeId = SchemaQualifiedType.TypeId(MetadataSearchBrowseNodeIds.QueueNodePrefix, OperationNames.PutMessage);
            string queueMessageTypeName = "QueueMessage" + MetadataTypeIds.GenericType;
            string queueMessageParamName = "QueueMessage";

            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void PutMessage(QueueMessageType QueueMessage)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.PutMessage);

            // Return Value Void
            om.OperationResult = OperationResult.Empty;

            // PutMessage
            om.OriginalName = OperationNames.PutMessage;
            om.OperationGroup = MetadataSearchBrowseNodeIds.QueueNodePrefix + queueName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            // Parameter QueueMessageType QueueMessage
            ComplexQualifiedType putMessageRequestParam = new ComplexQualifiedType(putMessageRequestTypeId);
            om.Parameters.Add(new OperationParameter(queueMessageParamName, OperationParameterDirection.In, putMessageRequestParam, false));

            // Resolve extra parameter type metadata here
            extraTypeMetadataResolved.Add(new AzureStorageTypes(putMessageRequestTypeId, queueMessageTypeName));

            return om;
        }

        #endregion

        #region BlobStorage Operations Metadata Resolver Implementation

        private OperationMetadata ResolveBlobStorageOperationMetadata(string containerName, string operationName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
           
            switch (operationName)
            {
                case OperationNames.AddBlob:
                    return ResolveBlobStorageAddBlobOperationMetadata(containerName, operationId, out extraTypeMetadataResolved);
                
                case OperationNames.DeleteBlob:
                    return ResolveBlobStorageDeleteBlobOperationMetadata(containerName, operationId, out extraTypeMetadataResolved);

                case OperationNames.GetBlob:
                    return ResolveBlobStorageGetBlobOperationMetadata(containerName, operationId, out extraTypeMetadataResolved);

                default:
                    throw new AdapterException("Cannot resolve metadata for operation identifier " + operationId);
            }
        }

        private OperationMetadata ResolveBlobStorageGetBlobOperationMetadata(string containerName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void GetBlob(BlobType blob)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.GetBlob);

            // Return Value void
            om.OperationResult = OperationResult.Empty;

            // GetMessage
            om.OriginalName = OperationNames.GetBlob;
            om.OperationGroup = MetadataSearchBrowseNodeIds.BlobNodePrefix + containerName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            // Parameter BlobType Blob
            om.Parameters.Add(new OperationParameter("Content", OperationParameterDirection.In, QualifiedType.StringType, false));

            // Resolve extra parameter type metadata here
            
            return om;
        }

        /// <summary>
        /// Resolve the Operation Metadata for Delete Blob Operation
        /// </summary>
        /// <param name="containerName">Name of the Container</param>
        /// <param name="operationId">Operation Id</param>
        /// <param name="extraTypeMetadataResolved"></param>
        /// <returns>Delete Blob Operation Metadata</returns>
        private OperationMetadata ResolveBlobStorageDeleteBlobOperationMetadata(string containerName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            //TODO Change with the correct SchemaType
            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void DeleteBlob(String Container, String Blob)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.DeleteBlob);

            // Return Value void
            om.OperationResult = OperationResult.Empty;

            // DeleteBlob
            om.OriginalName = OperationNames.DeleteBlob;
            om.OperationGroup = MetadataSearchBrowseNodeIds.BlobNodePrefix + containerName;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;

            // Parameter String Container Name
            om.Parameters.Add(new OperationParameter("ContainerName", OperationParameterDirection.In, QualifiedType.StringType, false));

            // Parameter String Blob url 
            om.Parameters.Add(new OperationParameter("BlobName", OperationParameterDirection.In, QualifiedType.StringType, false));

            // Resolve extra parameter type metadata here
            return om;
        }

        /// <summary>
        /// Resolve the Operation Metadata for Add Blob Operation
        /// </summary>
        /// <param name="containerName">Name of the Container</param>
        /// <param name="operationId">Operation Id</param>
        /// <param name="extraTypeMetadataResolved"></param>
        /// <returns>Add Blob Operation Metadata</returns>
        private OperationMetadata ResolveBlobStorageAddBlobOperationMetadata(string containerName, string operationId, out TypeMetadataCollection extraTypeMetadataResolved)
        {
            //TODO Change with the correct SchemaType

            string addBlobRequest = OperationNames.AddBlob + WsdlBuilderConstants.OPERATION_REQUEST_SUFFIX;
            string addBlobRequestTypeId = SchemaQualifiedType.TypeId(MetadataSearchBrowseNodeIds.BlobNodePrefix, OperationNames.AddBlob);
            string addBlobRequestTypeName = addBlobRequest + MetadataTypeIds.GenericType;
            string addBlobRequestParamName = OperationNames.AddBlob + WsdlBuilderConstants.PARAMETER_REQUEST_SUFFIX;

            extraTypeMetadataResolved = new TypeMetadataCollection();

            // syntax: void BlobMessage(AddMessageRequestType BlobMessageRequest)
            ParameterizedOperationMetadata om = new ParameterizedOperationMetadata(operationId, OperationNames.AddBlob);

            // Return Value Void
            //ComplexQualifiedType addBlobResponse = new ComplexQualifiedType("Types/BlobMessageResponse");
            //om.OperationResult = new OperationResult(BlobMessageResponse, false);
            om.OperationResult = OperationResult.Empty;

            // AddBlob
            om.OriginalName = OperationNames.AddBlob;
            om.OperationGroup = MetadataSearchBrowseNodeIds.BlobNodePrefix + containerName ;
            om.Description = Resources.AddBlobDescription;
            om.OperationNamespace = AzureStorageAdapter.SERVICENAMESPACE;
          
            // Parameter BlobMessageRequestType BlobMessageRequest
            ComplexQualifiedType addBlobRequestParam = new ComplexQualifiedType(addBlobRequestTypeId);
            om.Parameters.Add(new OperationParameter(addBlobRequestParamName, OperationParameterDirection.In, addBlobRequestParam, false));

            // Resolve extra parameter type metadata here
            extraTypeMetadataResolved.Add(new AzureStorageQualifiedType(addBlobRequestTypeId, addBlobRequestTypeName));
                     
            return om;
        }

        #endregion

        #region Implementation

        #endregion
    }
}
